﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Remoting.Messaging;
using BCMS.Business.DataContract;
using System.Windows.Forms;
using BCMS.Settings;

namespace BCMS.Business.Implementation
{
    public class AsyncProcessor
    {
        private CouponInfo _coupon;
        private InsertRecordDelegate _invokeMe;
        private ProgressBar _progress;
        private Label _elapsed;
        private Label _remain;
        private Label _status;
        private Label _done;
        private Label _total;
        private Button _trigger;

        private int _totalRecord;
        private int _recordNo;
        private DateTime _startTime;

        private delegate void InsertRecordDelegate(CouponInfo item);

        public AsyncProcessor(CouponInfo item, int totalRecord, int recordNo, DateTime starttime, ProgressBar progress, Label done, Label total, Label elapsed, Label remain, Label status, Button trigger)
        {
            _coupon = item;
            _totalRecord = totalRecord;
            _recordNo = recordNo;
            _progress = progress;
            _done = done;
            _startTime = starttime;
            _total = total;
            _elapsed = elapsed;
            _remain = remain;
            _status = status;
            _trigger = trigger;

            _invokeMe = new InsertRecordDelegate(StaticDAL.InsertNewCoupon);
        }

        public void Execute()
        {
            try
            {
                //Update UI here
                _invokeMe.BeginInvoke(_coupon, this.CallBack, null);
            }
            catch (System.Exception ex)
            {
                throw ex;
            }
        }

        private void CallBack(IAsyncResult ar)
        {
            try
            {
                AsyncResult result = (AsyncResult)ar;
                // grab the delegate
                InsertRecordDelegate del = (InsertRecordDelegate)result.AsyncDelegate;

                del.EndInvoke(ar);
                //Update UI here
                int completed = Convert.ToInt32(_recordNo * 100.0 / _totalRecord);

                MethodInvoker updateUI = delegate
                {
                    if ((completed % 5).Equals(0))
                    {
                        _progress.Value = _recordNo;
                        _done.Text = completed.ToString();
                        _total.Text = _recordNo.ToString("N0");
                    }

                    if (_recordNo.Equals(_totalRecord))
                    {
                        _status.Text = "Done";
                        _total.Text = _totalRecord.ToString();
                    }
                };
                if (_progress.InvokeRequired || _done.InvokeRequired)
                {
                    _progress.Invoke(updateUI);
                    _done.Invoke(updateUI);
                    _status.Invoke(updateUI);
                }
                else
                    updateUI();

                MethodInvoker TimeRelatedParam = delegate
                {
                    if ((completed % 5).Equals(0))
                    {
                        TimeSpan execTime = DateTime.Now - _startTime;
                        int speed = Convert.ToInt32(_recordNo / execTime.TotalSeconds + 1);
                        _elapsed.Text = execTime.Minutes.ToString("00") + " : " +
                                        execTime.Seconds.ToString("00") + " : " +
                                        execTime.Milliseconds.ToString("00");

                        TimeSpan estimateExec = new TimeSpan(0, 0,
                                        Convert.ToInt32((_totalRecord - _recordNo) / speed));
                        _remain.Text = estimateExec.Minutes.ToString("00") + " : " +
                                        estimateExec.Seconds.ToString("00") + " : " +
                                        estimateExec.Milliseconds.ToString("00"); ;
                    }
                };
                if (_elapsed.InvokeRequired || _remain.InvokeRequired)
                {
                    _elapsed.Invoke(TimeRelatedParam);
                    _remain.Invoke(TimeRelatedParam);
                }
                else
                    TimeRelatedParam();
            }
            catch 
            {
                MethodInvoker updateStatus = delegate
                {
                    _status.Text = "ERROR";
                };
                if (_status.InvokeRequired)
                    _remain.Invoke(updateStatus);
                return;
            }
        }
    }
}
